示例#1
0
文件: Nca.cs 项目: garoxas/LibHac
        public IStorage OpenStorageWithPatch(Nca patchNca, int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    rawStorage = OpenRawStorageWithPatch(patchNca, index);
            NcaFsHeader header     = patchNca.GetFsHeader(index);

            return(CreateVerificationStorage(integrityCheckLevel, header, rawStorage));
        }
示例#2
0
        public IFileSystem OpenFileSystem(int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    storage = OpenStorage(index, integrityCheckLevel);
            NcaFsHeader header  = Header.GetFsHeader(index);

            return(OpenFileSystem(storage, header));
        }
示例#3
0
        private IStorage OpenAesCtrExStorage(IStorage baseStorage, int index)
        {
            NcaFsHeader    fsHeader = Header.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 = new CachedStorage(new Aes128CtrStorage(baseStorage.Slice(bktrOffset, bktrSize), key, counter, true), 4, true);

            IStorage encryptionBucketTreeData = bucketTreeData.Slice(info.EncryptionTreeOffset - bktrOffset);
            IStorage decStorage = new Aes128CtrExStorage(baseStorage.Slice(0, dataSize), encryptionBucketTreeData, key, counterEx, true);

            decStorage = new CachedStorage(decStorage, 0x4000, 4, true);

            return(new ConcatenationStorage(new[] { decStorage, bucketTreeData }, true));
        }
示例#4
0
        public IFileSystem OpenFileSystemWithPatch(Nca patchNca, int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    storage = OpenStorageWithPatch(patchNca, index, integrityCheckLevel);
            NcaFsHeader header  = patchNca.Header.GetFsHeader(index);

            return(OpenFileSystem(storage, header));
        }
示例#5
0
        public static Validity VerifySection(this Nca nca, Nca patchNca, int index, IProgressReport logger = null, bool quiet = false)
        {
            NcaFsHeader sect     = nca.Header.GetFsHeader(index);
            NcaHashType hashType = sect.HashType;

            if (hashType != NcaHashType.Sha256 && hashType != NcaHashType.Ivfc)
            {
                return(Validity.Unchecked);
            }

            var stream = nca.OpenStorageWithPatch(patchNca, index, IntegrityCheckLevel.IgnoreOnInvalid)
                         as HierarchicalIntegrityVerificationStorage;

            if (stream == null)
            {
                return(Validity.Unchecked);
            }

            if (!quiet)
            {
                logger?.LogMessage($"Verifying section {index}...");
            }
            Validity validity = stream.Validate(true, logger);

            return(validity);
        }
示例#6
0
        // ReSharper restore UnusedParameter.Local

        private IStorage OpenAesCtrStorage(IStorage baseStorage, int index)
        {
            NcaFsHeader fsHeader = Header.GetFsHeader(index);

            byte[] key     = GetContentKey(NcaKeyType.AesCtr);
            byte[] counter = Aes128CtrStorage.CreateCounter(fsHeader.Counter, Header.GetSectionStartOffset(index));

            var aesStorage = new Aes128CtrStorage(baseStorage, key, Header.GetSectionStartOffset(index), counter, true);

            return(new CachedStorage(aesStorage, 0x4000, 4, true));
        }
示例#7
0
文件: Nca.cs 项目: garoxas/LibHac
        public IStorage OpenStorage(int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    rawStorage = OpenRawStorage(index);
            NcaFsHeader header     = GetFsHeader(index);

            if (header.EncryptionType == NcaEncryptionType.AesCtrEx)
            {
                return(rawStorage.Slice(0, header.GetPatchInfo().RelocationTreeOffset));
            }

            return(CreateVerificationStorage(integrityCheckLevel, header, rawStorage));
        }
示例#8
0
        internal void GenerateAesCounter(int sectionIndex, Ncm.ContentType type, int minorVersion)
        {
            int counterType;
            int counterVersion;

            NcaFsHeader header = Header.GetFsHeader(sectionIndex);

            if (header.EncryptionType != NcaEncryptionType.AesCtr &&
                header.EncryptionType != NcaEncryptionType.AesCtrEx)
            {
                return;
            }

            switch (type)
            {
            case Ncm.ContentType.Program:
                counterType = sectionIndex + 1;
                break;

            case Ncm.ContentType.HtmlDocument:
                counterType = (int)Ncm.ContentType.HtmlDocument;
                break;

            case Ncm.ContentType.LegalInformation:
                counterType = (int)Ncm.ContentType.LegalInformation;
                break;

            default:
                counterType = 0;
                break;
            }

            // Version of firmware NCAs appears to always be 0
            // Haven't checked delta fragment NCAs
            switch (Header.ContentType)
            {
            case NcaContentType.Program:
            case NcaContentType.Manual:
                counterVersion = Math.Max(minorVersion - 1, 0);
                break;

            case NcaContentType.PublicData:
                counterVersion = minorVersion << 16;
                break;

            default:
                counterVersion = 0;
                break;
            }

            header.CounterType    = counterType;
            header.CounterVersion = counterVersion;
        }
示例#9
0
        private IFileSystem OpenFileSystem(IStorage storage, NcaFsHeader header)
        {
            switch (header.FormatType)
            {
            case NcaFormatType.Pfs0:
                return(new PartitionFileSystem(storage));

            case NcaFormatType.Romfs:
                return(new RomFsFileSystem(storage));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#10
0
文件: Nca.cs 项目: garoxas/LibHac
        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));
        }
示例#11
0
        public IStorage OpenRawStorageWithPatch(Nca patchNca, int index)
        {
            IStorage patchStorage = patchNca.OpenRawStorage(index);
            IStorage baseStorage  = SectionExists(index) ? OpenRawStorage(index) : new NullStorage();

            NcaFsHeader    header    = patchNca.Header.GetFsHeader(index);
            NcaFsPatchInfo patchInfo = header.GetPatchInfo();

            if (patchInfo.RelocationTreeSize == 0)
            {
                return(patchStorage);
            }

            IStorage relocationTableStorage = patchStorage.Slice(patchInfo.RelocationTreeOffset, patchInfo.RelocationTreeSize);

            return(new IndirectStorage(relocationTableStorage, true, baseStorage, patchStorage));
        }
示例#12
0
        public IStorage OpenStorageWithPatch(Nca patchNca, int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    rawStorage = OpenRawStorageWithPatch(patchNca, index);
            NcaFsHeader header     = patchNca.Header.GetFsHeader(index);

            switch (header.HashType)
            {
            case NcaHashType.Sha256:
                return(InitIvfcForPartitionFs(header.GetIntegrityInfoSha256(), rawStorage, integrityCheckLevel, true));

            case NcaHashType.Ivfc:
                return(InitIvfcForRomFs(header.GetIntegrityInfoIvfc(), rawStorage, integrityCheckLevel, true));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#13
0
        public IStorage OpenStorage(int index, IntegrityCheckLevel integrityCheckLevel)
        {
            IStorage    rawStorage = OpenRawStorage(index);
            NcaFsHeader header     = Header.GetFsHeader(index);

            if (header.EncryptionType == NcaEncryptionType.AesCtrEx)
            {
                return(rawStorage.Slice(0, header.GetPatchInfo().RelocationTreeOffset));
            }

            switch (header.HashType)
            {
            case NcaHashType.Sha256:
                return(InitIvfcForPartitionFs(header.GetIntegrityInfoSha256(), rawStorage, integrityCheckLevel, true));

            case NcaHashType.Ivfc:
                return(InitIvfcForRomFs(header.GetIntegrityInfoIvfc(), rawStorage, integrityCheckLevel, true));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#14
0
        private IStorage OpenDecryptedStorage(IStorage baseStorage, int index)
        {
            NcaFsHeader header = Header.GetFsHeader(index);

            switch (header.EncryptionType)
            {
            case NcaEncryptionType.None:
                return(baseStorage);

            case NcaEncryptionType.XTS:
                return(OpenAesXtsStorage(baseStorage, index));

            case NcaEncryptionType.AesCtr:
                return(OpenAesCtrStorage(baseStorage, index));

            case NcaEncryptionType.AesCtrEx:
                return(OpenAesCtrExStorage(baseStorage, index));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#15
0
        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);
        }
示例#16
0
文件: Nca.cs 项目: garoxas/LibHac
        private IStorage CreateVerificationStorage(IntegrityCheckLevel integrityCheckLevel, NcaFsHeader header,
                                                   IStorage rawStorage)
        {
            switch (header.HashType)
            {
            case NcaHashType.Sha256:
                return(InitIvfcForPartitionFs(header.GetIntegrityInfoSha256(), rawStorage, integrityCheckLevel,
                                              true));

            case NcaHashType.Ivfc:
                // The FS header of an NCA0 section with IVFC verification must be manually skipped
                if (Header.IsNca0())
                {
                    rawStorage = rawStorage.Slice(0x200);
                }

                return(InitIvfcForRomFs(header.GetIntegrityInfoIvfc(), rawStorage, integrityCheckLevel, true));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#17
0
        public static Validity ValidateSectionMasterHash(this Nca nca, int index)
        {
            if (!nca.SectionExists(index))
            {
                throw new ArgumentException(nameof(index), Messages.NcaSectionMissing);
            }
            if (!nca.CanOpenSection(index))
            {
                return(Validity.MissingKey);
            }

            NcaFsHeader header = nca.Header.GetFsHeader(index);

            // The base data is needed to validate the hash, so use a trick involving the AES-CTR extended
            // encryption table to check if the decryption is invalid.
            // todo: If the patch replaces the data checked by the master hash, use that directly
            if (header.IsPatchSection())
            {
                if (header.EncryptionType != NcaEncryptionType.AesCtrEx)
                {
                    return(Validity.Unchecked);
                }

                Validity ctrExValidity = ValidateCtrExDecryption(nca, index);
                return(ctrExValidity == Validity.Invalid ? Validity.Invalid : Validity.Unchecked);
            }

            byte[] expectedHash;
            long   offset;
            long   size;

            switch (header.HashType)
            {
            case NcaHashType.Ivfc:
                NcaFsIntegrityInfoIvfc ivfcInfo = header.GetIntegrityInfoIvfc();

                expectedHash = ivfcInfo.MasterHash.ToArray();
                offset       = ivfcInfo.GetLevelOffset(0);
                size         = 1 << ivfcInfo.GetLevelBlockSize(0);

                break;

            case NcaHashType.Sha256:
                NcaFsIntegrityInfoSha256 sha256Info = header.GetIntegrityInfoSha256();
                expectedHash = sha256Info.MasterHash.ToArray();

                offset = sha256Info.GetLevelOffset(0);
                size   = sha256Info.GetLevelSize(0);

                break;

            default:
                return(Validity.Unchecked);
            }

            IStorage storage = nca.OpenRawStorage(index);

            var data = new byte[size];

            storage.Read(offset, data).ThrowIfFailure();

            var actualHash = new byte[Sha256.DigestSize];

            Sha256.GenerateSha256Hash(data, actualHash);

            if (Utilities.ArraysEqual(expectedHash, actualHash))
            {
                return(Validity.Valid);
            }

            return(Validity.Invalid);
        }