예제 #1
0
파일: Package1.cs 프로젝트: Icyelut/LibHac
        private Result ParseStage1()
        {
            // Erista package1ldr is stored unencrypted, so we can always directly read the size
            // field at the end of package1ldr.

            // Mariko package1ldr is stored encrypted. If we're able to decrypt it,
            // directly read the size field at the end of package1ldr.

            IsModern = !IsLegacyImpl();
            int stage1Size = IsModern ? ModernStage1Size : LegacyStage1Size;

            if (IsMariko && !IsDecrypted)
            {
                // If we're not able to decrypt the Mariko package1ldr, calculate the size by subtracting
                // the known package1ldr size from the total size in the OEM header.
                Pk11Size = MarikoOemHeader.Size - stage1Size;
                return(Result.Success);
            }

            // Read the package1ldr footer
            int footerOffset = stage1Size - Unsafe.SizeOf <Package1Stage1Footer>();

            Result rc = BodyStorage.Read(footerOffset, SpanHelpers.AsByteSpan(ref _stage1Footer));

            if (rc.IsFailure())
            {
                return(rc);
            }

            // Get the PK11 size from the field in the unencrypted stage 1 footer
            Pk11Size = _stage1Footer.Pk11Size;

            return(Result.Success);
        }
예제 #2
0
파일: Package1.cs 프로젝트: Icyelut/LibHac
        private bool TryFindEristaKeyRevision()
        {
            // Package1 has no indication of which key it's encrypted with,
            // so we must test each known key to find one that works

            var decHeader = new Package1Pk11Header();

            int       start     = IsModern ? 6 : 0;
            int       end       = IsModern ? 0x20 : 6;
            Decryptor decryptor = IsModern ? Crypto.Aes.DecryptCbc128 : (Decryptor)Crypto.Aes.DecryptCtr128;

            for (int i = start; i < end; i++)
            {
                decryptor(SpanHelpers.AsByteSpan(ref _pk11Header), SpanHelpers.AsByteSpan(ref decHeader),
                          KeySet.Package1Keys[i], _stage1Footer.Iv);

                if (decHeader.Magic == Package1Pk11Header.ExpectedMagic)
                {
                    KeyRevision = (byte)i;
                    _pk11Header = decHeader;
                    return(true);
                }
            }

            return(false);
        }
        private Result CreateExtraDataForTest(IFileSystem fileSystem, U8Span path, int saveDataSize)
        {
            fileSystem.DeleteFile(path).IgnoreResult();

            Result rc = fileSystem.CreateFile(path, Unsafe.SizeOf <SaveDataExtraData>());

            if (rc.IsFailure())
            {
                return(rc);
            }

            var extraData = new SaveDataExtraData();

            extraData.DataSize = saveDataSize;

            rc = fileSystem.OpenFile(out IFile file, path, OpenMode.ReadWrite);
            if (rc.IsFailure())
            {
                return(rc);
            }

            using (file)
            {
                rc = file.Write(0, SpanHelpers.AsByteSpan(ref extraData), WriteOption.Flush);
                if (rc.IsFailure())
                {
                    return(rc);
                }
            }

            return(Result.Success);
        }
예제 #4
0
        public Result ReadEntryCount(out int count)
        {
            UnsafeHelpers.SkipParamInit(out count);

            // This should only be called at the start of reading stream.
            Assert.SdkRequiresEqual(_offset, 0);

            // Read and validate header.
            var header = new KeyValueArchiveHeader();

            Result rc = Read(SpanHelpers.AsByteSpan(ref header));

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (!header.IsValid())
            {
                return(ResultKvdb.InvalidKeyValue.Log());
            }

            count = header.EntryCount;
            return(Result.Success);
        }
예제 #5
0
        public Result ReadDatabaseFromBuffer(ReadOnlySpan <byte> data)
        {
            KvDict.Clear();

            var reader = new ImkvdbReader(data);

            Result rc = reader.ReadHeader(out int entryCount);

            if (rc.IsFailure())
            {
                return(rc);
            }

            for (int i = 0; i < entryCount; i++)
            {
                rc = reader.ReadEntry(out ReadOnlySpan <byte> keyBytes, out ReadOnlySpan <byte> valueBytes);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                Debug.Assert(keyBytes.Length == Unsafe.SizeOf <TKey>());

                var key = new TKey();
                keyBytes.CopyTo(SpanHelpers.AsByteSpan(ref key));

                byte[] value = valueBytes.ToArray();

                KvDict.Add(key, value);
            }

            return(Result.Success);
        }
예제 #6
0
        public Result Initialize(IStorage kipData)
        {
            if (kipData is null)
            {
                return(ResultLibHac.NullArgument.Log());
            }

            // Verify there's enough data to read the header
            Result rc = kipData.GetSize(out long kipSize);

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (kipSize < Unsafe.SizeOf <KipHeader>())
            {
                return(ResultLibHac.InvalidKipFileSize.Log());
            }

            rc = kipData.Read(0, SpanHelpers.AsByteSpan(ref _header));
            if (rc.IsFailure())
            {
                return(rc);
            }

            if (!_header.IsValid)
            {
                return(ResultLibHac.InvalidKipMagic.Log());
            }

            KipStorage = kipData;
            return(Result.Success);
        }
예제 #7
0
        public static Result ConvertToFspPath(out FspPath fspPath, ReadOnlySpan <byte> path)
        {
            UnsafeHelpers.SkipParamInit(out fspPath);

            int length = StringUtils.Copy(SpanHelpers.AsByteSpan(ref fspPath), path, PathTool.EntryNameLengthMax + 1);

            if (length >= PathTool.EntryNameLengthMax + 1)
            {
                return(ResultFs.TooLongPath.Log());
            }

            Result rc = PathFormatter.SkipMountName(out ReadOnlySpan <byte> pathWithoutMountName, out _,
                                                    new U8Span(path));

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (!WindowsPath12.IsWindowsPath(pathWithoutMountName, true))
            {
                Replace(SpanHelpers.AsByteSpan(ref fspPath).Slice(0, 0x300), AltDirectorySeparator, DirectorySeparator);
            }
            else if (fspPath.Str[0] == DirectorySeparator && fspPath.Str[1] == DirectorySeparator)
            {
                SpanHelpers.AsByteSpan(ref fspPath)[0] = AltDirectorySeparator;
                SpanHelpers.AsByteSpan(ref fspPath)[1] = AltDirectorySeparator;
            }

            return(Result.Success);
        }
        public void Initialize_InitialExtraDataIsEmpty()
        {
            (IFileSystem _, DirectorySaveDataFileSystem saveFs) = CreateFileSystemInternal();

            Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
            Assert.True(SpanHelpers.AsByteSpan(ref extraData).IsZeros());
        }
예제 #9
0
            public Result SetCommittedProvisionally()
            {
                IFile contextFile = null;

                try
                {
                    Result rc = _fileSystem.OpenFile(out contextFile, ContextFileName, OpenMode.ReadWrite);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    _context.State = CommitState.ProvisionallyCommitted;

                    rc = contextFile.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    rc = contextFile.Flush();
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }
                }
                finally
                {
                    contextFile?.Dispose();
                }

                return(_fileSystem.Commit());
            }
        public Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
        {
            UnsafeHelpers.SkipParamInit(out rangeInfo);
            rangeInfo.Clear();

            if (operationId == (int)OperationId.InvalidateCache)
            {
                Result rc = BaseFile.OperateRange(Span <byte> .Empty, OperationId.InvalidateCache, offset, size,
                                                  ReadOnlySpan <byte> .Empty);
                if (rc.IsFailure())
                {
                    return(rc);
                }
            }
            else if (operationId == (int)OperationId.QueryRange)
            {
                Unsafe.SkipInit(out QueryRangeInfo info);

                Result rc = BaseFile.OperateRange(SpanHelpers.AsByteSpan(ref info), OperationId.QueryRange, offset, size,
                                                  ReadOnlySpan <byte> .Empty);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rangeInfo.Merge(in info);
            }

            return(Result.Success);
        }
예제 #11
0
        public Result GetKeyValueSize(out int keySize, out int valueSize)
        {
            UnsafeHelpers.SkipParamInit(out keySize, out valueSize);

            // This should only be called after ReadEntryCount.
            Assert.SdkNotEqual(_offset, 0);

            // Peek the next entry header.
            Unsafe.SkipInit(out KeyValueArchiveEntryHeader header);

            Result rc = Peek(SpanHelpers.AsByteSpan(ref header));

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (!header.IsValid())
            {
                return(ResultKvdb.InvalidKeyValue.Log());
            }

            keySize   = header.KeySize;
            valueSize = header.ValueSize;

            return(Result.Success);
        }
예제 #12
0
        public Result Get(out SaveDataIndexerValue value, ref SaveDataAttribute key)
        {
            value = default;

            lock (Locker)
            {
                Result rc = Initialize();
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rc = EnsureKvDatabaseLoaded(false);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rc = KvDatabase.Get(ref key, SpanHelpers.AsByteSpan(ref value));

                if (rc.IsFailure())
                {
                    return(ResultFs.TargetNotFound.LogConverted(rc));
                }

                return(Result.Success);
            }
        }
예제 #13
0
        public Result Initialize(IFile kipFile)
        {
            if (kipFile is null)
            {
                return(ResultLibHac.NullArgument.Log());
            }

            Result rc = kipFile.Read(out long bytesRead, 0, SpanHelpers.AsByteSpan(ref _header), ReadOption.None);

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (bytesRead != Unsafe.SizeOf <KipHeader>())
            {
                return(ResultLibHac.InvalidKipFileSize.Log());
            }

            if (!_header.IsValid)
            {
                return(ResultLibHac.InvalidKipMagic.Log());
            }

            KipFile = kipFile;
            return(Result.Success);
        }
예제 #14
0
        private bool IsUpdateApplied(string titleId, out string version)
        {
            string updatePath = "(unknown)";

            try
            {
                (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateData(_virtualFileSystem, titleId, 0, out updatePath);

                if (patchNca != null && controlNca != null)
                {
                    ApplicationControlProperty controlData = new ApplicationControlProperty();

                    controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();

                    nacpFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();

                    version = controlData.DisplayVersion.ToString();

                    return(true);
                }
            }
            catch (InvalidDataException)
            {
                Logger.Warning?.Print(LogClass.Application,
                                      $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {updatePath}");
            }
            catch (MissingKeyException exception)
            {
                Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {updatePath}");
            }

            version = "";

            return(false);
        }
예제 #15
0
        public IStorage OpenIni1()
        {
            if (Header.SectionSizes[1] == 0)
            {
                IStorage kernelStorage = OpenKernel();

                var reader = new BinaryReader(kernelStorage.AsStream());
                for (int i = 0; i < (Header.SectionSizes[0] / sizeof(uint)) - 1; i++)
                {
                    if (reader.ReadUInt32() == 0xD51C403E) // end indicator for KernelMap
                    {
                        break;
                    }
                }

                reader.BaseStream.Seek(-Unsafe.SizeOf <KernelMap>(), SeekOrigin.Current);

                KernelMap map = new KernelMap();
                reader.Read(SpanHelpers.AsByteSpan(ref map));

                return(new CachedStorage(kernelStorage.Slice(map.Ini1StartOffset), 0x4000, 4, true));
            }
            else
            {
                return(new CachedStorage(OpenSection(1), 0x4000, 4, true));
            }
        }
예제 #16
0
        // nn::friends::GetPlayHistoryRegistrationKey(b8 unknown, nn::account::Uid) -> buffer<nn::friends::PlayHistoryRegistrationKey, 0x1a>
        public ResultCode GetPlayHistoryRegistrationKey(ServiceCtx context)
        {
            bool   unknownBool = context.RequestData.ReadBoolean();
            UserId userId      = context.RequestData.ReadStruct <UserId>();

            context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(0x40UL);

            ulong bufferPosition = context.Request.RecvListBuff[0].Position;

            if (userId.IsNull)
            {
                return(ResultCode.InvalidArgument);
            }

            // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance.

            byte[] randomBytes = new byte[8];
            Random random      = new Random();

            random.NextBytes(randomBytes);

            // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance.
            //       Then call nn::friends::detail::service::core::AccountStorageManager::GetInstance and store the instance.
            //       Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid.
            //       And store it in the savedata 8000000000000080 in the friends:/uid.bin file.

            Array16 <byte> randomGuid = new Array16 <byte>();

            Guid.NewGuid().ToByteArray().AsSpan().CopyTo(randomGuid.ToSpan());

            PlayHistoryRegistrationKey playHistoryRegistrationKey = new PlayHistoryRegistrationKey
            {
                Type        = 0x101,
                KeyIndex    = (byte)(randomBytes[0] & 7),
                UserIdBool  = 0,                           // TODO: Find it.
                UnknownBool = (byte)(unknownBool ? 1 : 0), // TODO: Find it.
                Reserved    = new Array11 <byte>(),
                Uuid        = randomGuid
            };

            ReadOnlySpan <byte> playHistoryRegistrationKeyBuffer = SpanHelpers.AsByteSpan(ref playHistoryRegistrationKey);

            /*
             *
             * NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer).
             *    We currently don't support play history and online services so we can use a blank key for now.
             *    Code for reference:
             *
             * byte[] hmacKey = new byte[0x20];
             *
             * HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey);
             * byte[]     hmacHash   = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer);
             *
             */

            context.Memory.Write(bufferPosition, playHistoryRegistrationKeyBuffer);
            context.Memory.Write(bufferPosition + 0x20, new byte[0x20]); // HmacHash

            return(ResultCode.Success);
        }
예제 #17
0
        public Result Initialize(SubStorage tableStorage)
        {
            // Read and verify the bucket tree header.
            // note: skip init
            var header = new BucketTree.Header();

            Result rc = tableStorage.Read(0, SpanHelpers.AsByteSpan(ref header));

            if (rc.IsFailure())
            {
                return(rc);
            }

            rc = header.Verify();
            if (rc.IsFailure())
            {
                return(rc);
            }

            // Determine extents.
            long nodeStorageSize    = QueryNodeStorageSize(header.EntryCount);
            long entryStorageSize   = QueryEntryStorageSize(header.EntryCount);
            long nodeStorageOffset  = QueryHeaderStorageSize();
            long entryStorageOffset = nodeStorageOffset + nodeStorageSize;

            // Initialize.
            var nodeStorage  = new SubStorage(tableStorage, nodeStorageOffset, nodeStorageSize);
            var entryStorage = new SubStorage(tableStorage, entryStorageOffset, entryStorageSize);

            return(Initialize(nodeStorage, entryStorage, header.EntryCount));
        }
예제 #18
0
        private Result Read(U8Span path, bool allowMissingMetaFile)
        {
            lock (Locker)
            {
                FileSystemClient fs = Server.GetFsClient();

                Result rc = fs.OpenFile(out FileHandle handle, path, OpenMode.Read);

                if (rc.IsFailure())
                {
                    if (ResultFs.PathNotFound.Includes(rc))
                    {
                        if (allowMissingMetaFile)
                        {
                            Count = 0;
                            return(Result.Success);
                        }

                        return(ResultBcat.NotFound.LogConverted(rc));
                    }

                    return(rc);
                }

                try
                {
                    Count = 0;
                    int header = 0;

                    // Verify the header value
                    rc = fs.ReadFile(out long bytesRead, handle, 0, SpanHelpers.AsByteSpan(ref header));
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    if (bytesRead != sizeof(int) || header != MetaFileHeaderValue)
                    {
                        return(ResultBcat.InvalidDeliveryCacheStorageFile.Log());
                    }

                    // Read all the file entries
                    Span <byte> buffer = MemoryMarshal.Cast <DeliveryCacheFileMetaEntry, byte>(Entries);
                    rc = fs.ReadFile(out bytesRead, handle, 4, buffer);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    Count = (int)((uint)bytesRead / Unsafe.SizeOf <DeliveryCacheFileMetaEntry>());

                    return(Result.Success);
                }
                finally
                {
                    fs.CloseFile(handle);
                }
            }
        }
예제 #19
0
파일: Utility.cs 프로젝트: leo60228/LibHac
        public static unsafe Result CopyDirectoryRecursively(IFileSystem destFileSystem, IFileSystem sourceFileSystem,
                                                             U8Span destPath, U8Span sourcePath, Span <byte> workBuffer)
        {
            var destPathBuf  = new FsPath();
            int originalSize = StringUtils.Copy(destPathBuf.Str, destPath);

            Abort.DoAbortUnless(originalSize < Unsafe.SizeOf <FsPath>());

            // Pin and recreate the span because C# can't use byref-like types in a closure
            int workBufferSize = workBuffer.Length;

            fixed(byte *pWorkBuffer = workBuffer)
            {
                // Copy the pointer to workaround CS1764.
                // IterateDirectoryRecursively won't store the delegate anywhere, so it should be safe
                byte *pWorkBuffer2 = pWorkBuffer;

                Result OnEnterDir(U8Span path, ref DirectoryEntry entry)
                {
                    // Update path, create new dir.
                    StringUtils.Concat(SpanHelpers.AsByteSpan(ref destPathBuf), entry.Name);
                    StringUtils.Concat(SpanHelpers.AsByteSpan(ref destPathBuf), DirectorySeparator);

                    return(destFileSystem.CreateDirectory(destPathBuf));
                }

                Result OnExitDir(U8Span path, ref DirectoryEntry entry)
                {
                    // Check we have a parent directory.
                    int len = StringUtils.GetLength(SpanHelpers.AsByteSpan(ref destPathBuf));

                    if (len < 2)
                    {
                        return(ResultFs.InvalidPathFormat.Log());
                    }

                    // Find previous separator, add null terminator
                    int cur = len - 2;

                    while (!PathTool.IsSeparator(SpanHelpers.AsByteSpan(ref destPathBuf)[cur]) && cur > 0)
                    {
                        cur--;
                    }

                    SpanHelpers.AsByteSpan(ref destPathBuf)[cur + 1] = StringTraits.NullTerminator;

                    return(Result.Success);
                }

                Result OnFile(U8Span path, ref DirectoryEntry entry)
                {
                    var buffer = new Span <byte>(pWorkBuffer2, workBufferSize);

                    return(CopyFile(destFileSystem, sourceFileSystem, destPathBuf, path, ref entry, buffer));
                }

                return(IterateDirectoryRecursively(sourceFileSystem, sourcePath, OnEnterDir, OnExitDir, OnFile));
            }
        }
예제 #20
0
        private ushort CalculateDeviceCrc()
        {
            UInt128 deviceId = Helper.GetDeviceId();

            ushort deviceIdCrc16 = Helper.CalculateCrc16(SpanHelpers.AsByteSpan(ref deviceId), 0, false);

            return(Helper.CalculateCrc16(AsSpan(), deviceIdCrc16, true));
        }
예제 #21
0
        public bool IsValidDeviceCrc()
        {
            UInt128 deviceId = Helper.GetDeviceId();

            ushort deviceIdCrc16 = Helper.CalculateCrc16(SpanHelpers.AsByteSpan(ref deviceId), 0, false);

            return(Helper.CalculateCrc16(AsSpan(), deviceIdCrc16, false) == 0);
        }
예제 #22
0
        private ushort CalculateDeviceCrc()
        {
            UInt128 deviceId = Helper.GetDeviceId();

            ushort deviceIdCrc16 = Helper.CalculateCrc16BE(SpanHelpers.AsByteSpan(ref deviceId));

            return(Helper.CalculateCrc16BE(AsSpanWithoutDeviceCrc(), deviceIdCrc16));
        }
예제 #23
0
            /// <summary>
            /// Initializes the bucket tree builder.
            /// </summary>
            /// <param name="headerStorage">The <see cref="SubStorage"/> the tree's header will be written to.Must be at least the size in bytes returned by <see cref="QueryHeaderStorageSize"/>.</param>
            /// <param name="nodeStorage">The <see cref="SubStorage"/> the tree's nodes will be written to. Must be at least the size in bytes returned by <see cref="QueryNodeStorageSize"/>.</param>
            /// <param name="entryStorage">The <see cref="SubStorage"/> the tree's entries will be written to. Must be at least the size in bytes returned by <see cref="QueryEntryStorageSize"/>.</param>
            /// <param name="nodeSize">The size of each node in the bucket tree. Must be a power of 2.</param>
            /// <param name="entrySize">The size of each entry that will be stored in the bucket tree.</param>
            /// <param name="entryCount">The exact number of entries that will be added to the bucket tree.</param>
            /// <returns>The <see cref="Result"/> of the operation.</returns>
            public Result Initialize(SubStorage headerStorage, SubStorage nodeStorage, SubStorage entryStorage,
                                     int nodeSize, int entrySize, int entryCount)
            {
                Assert.True(entrySize >= sizeof(long));
                Assert.True(nodeSize >= entrySize + Unsafe.SizeOf <NodeHeader>());
                Assert.True(NodeSizeMin <= nodeSize && nodeSize <= NodeSizeMax);
                Assert.True(BitUtil.IsPowerOfTwo(nodeSize));

                if (headerStorage is null || nodeStorage is null || entryStorage is null)
                {
                    return(ResultFs.NullptrArgument.Log());
                }

                // Set the builder parameters
                NodeSize   = nodeSize;
                EntrySize  = entrySize;
                EntryCount = entryCount;

                EntriesPerEntrySet   = GetEntryCount(nodeSize, entrySize);
                OffsetsPerNode       = GetOffsetCount(nodeSize);
                CurrentL2OffsetIndex = GetNodeL2Count(nodeSize, entrySize, entryCount);

                // Create and write the header
                var header = new Header();

                header.Format(entryCount);
                Result rc = headerStorage.Write(0, SpanHelpers.AsByteSpan(ref header));

                if (rc.IsFailure())
                {
                    return(rc);
                }

                // Allocate buffers for the L1 node and entry sets
                _l1Node.Allocate(nodeSize);
                _entrySet.Allocate(nodeSize);

                int entrySetCount = GetEntrySetCount(nodeSize, entrySize, entryCount);

                // Allocate an L2 node buffer if there are more entry sets than will fit in the L1 node
                if (OffsetsPerNode < entrySetCount)
                {
                    _l2Node.Allocate(nodeSize);
                }

                _l1Node.FillZero();
                _l2Node.FillZero();
                _entrySet.FillZero();

                NodeStorage  = nodeStorage;
                EntryStorage = entryStorage;

                // Set the initial position
                CurrentEntryIndex = 0;
                CurrentOffset     = -1;

                return(Result.Success);
            }
예제 #24
0
        private void DecryptHeader(ReadOnlySpan <byte> key, ref Package2Meta source, ref Package2Meta dest)
        {
            Buffer16 iv = source.HeaderIv;

            Aes.DecryptCtr128(SpanHelpers.AsByteSpan(ref source), SpanHelpers.AsByteSpan(ref dest), key, iv);

            // Copy the IV to the output because the IV field will be garbage after "decrypting" it
            Unsafe.As <Package2Meta, Buffer16>(ref dest) = iv;
        }
예제 #25
0
        public void WriteHeader(int entryCount)
        {
            // This should only be called at start of write.
            Assert.SdkEqual(_offset, 0);

            var header = new KeyValueArchiveHeader(entryCount);

            Write(SpanHelpers.AsByteSpan(ref header));
        }
예제 #26
0
        private void AddUpdate(string path, bool showErrorDialog = true)
        {
            if (File.Exists(path))
            {
                using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());

                    try
                    {
                        (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0);

                        if (controlNca != null && patchNca != null)
                        {
                            ApplicationControlProperty controlData = new ApplicationControlProperty();

                            controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
                            nacpFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();

                            RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}");
                            radioButton.JoinGroup(_noUpdateRadioButton);

                            _availableUpdatesBox.Add(radioButton);
                            _radioButtonToPathDictionary.Add(radioButton, path);

                            radioButton.Show();
                            radioButton.Active = true;
                        }
                        else
                        {
                            GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
                        }
                    }
                    catch (InvalidDataException exception)
                    {
                        Logger.Error?.Print(LogClass.Application, $"{exception.Message}. Errored File: {path}");

                        if (showErrorDialog)
                        {
                            GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
                        }
                    }
                    catch (MissingKeyException exception)
                    {
                        Logger.Error?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {path}");

                        if (showErrorDialog)
                        {
                            GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", $"Your key set is missing a key with the name: {exception.Name}");
                        }
                    }
                }
            }
        }
예제 #27
0
        public void WriteEntry(ReadOnlySpan <byte> key, ReadOnlySpan <byte> value)
        {
            // This should only be called after writing header.
            Assert.SdkNotEqual(_offset, 0);

            var header = new KeyValueArchiveEntryHeader(key.Length, value.Length);

            Write(SpanHelpers.AsByteSpan(ref header));
            Write(key);
            Write(value);
        }
예제 #28
0
        public static ServiceName Encode(ReadOnlySpan <char> name)
        {
            var outName = new ServiceName();
            int length  = Math.Min(MaxLength, name.Length);

            for (int i = 0; i < length; i++)
            {
                SpanHelpers.AsByteSpan(ref outName)[i] = (byte)name[i];
            }

            return(outName);
        }
예제 #29
0
        public Result Add(out ulong saveDataId, ref SaveDataAttribute key)
        {
            saveDataId = default;

            lock (Locker)
            {
                Result rc = Initialize();
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rc = EnsureKvDatabaseLoaded(false);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                SaveDataIndexerValue value = default;

                rc = KvDatabase.Get(ref key, SpanHelpers.AsByteSpan(ref value));

                if (rc.IsSuccess())
                {
                    return(ResultFs.SaveDataPathAlreadyExists.Log());
                }

                LastPublishedId++;
                ulong newSaveDataId = LastPublishedId;

                value = new SaveDataIndexerValue {
                    SaveDataId = newSaveDataId
                };

                rc = KvDatabase.Set(ref key, SpanHelpers.AsByteSpan(ref value));

                if (rc.IsFailure())
                {
                    LastPublishedId--;
                    return(rc);
                }

                rc = AdjustOpenedInfoReaders(ref key);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                saveDataId = newSaveDataId;
                return(Result.Success);
            }
        }
예제 #30
0
        /// <summary>
        /// Verifies the signature of the package.
        /// </summary>
        /// <returns>The <see cref="Result"/> of the operation.
        /// <see cref="Result.Success"/> if the signature is valid.</returns>
        public Result VerifySignature()
        {
            Unsafe.SkipInit(out Package2Meta meta);
            Span <byte> metaBytes = SpanHelpers.AsByteSpan(ref meta);

            Result rc = _storage.Read(Package2Header.SignatureSize, metaBytes);

            if (rc.IsFailure())
            {
                return(rc);
            }

            return(_header.VerifySignature(_keySet.Package2SigningKeyParams.Modulus, metaBytes));
        }