Example #1
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);
        }
Example #2
0
        public NcaHeader(BinaryReader reader, Keyset keyset)
        {
            Signature1 = reader.ReadBytes(0x100);
            Signature2 = reader.ReadBytes(0x100);
            Magic      = reader.ReadAscii(4);

            if (!Magic.StartsWith("NCA") || Magic[3] < '0' || Magic[3] > '9')
            {
                throw new InvalidDataException("Unable to decrypt NCA header, or the file is not an NCA file.");
            }

            Version = Magic[3] - '0';
            if (Version != 2 && Version != 3)
            {
                throw new NotSupportedException($"NCA version {Version} is not supported.");
            }

            reader.BaseStream.Position -= 4;
            SignatureData    = reader.ReadBytes(0x200);
            FixedSigValidity = Crypto.Rsa2048PssVerify(SignatureData, Signature1, keyset.NcaHdrFixedKeyModulus);

            reader.BaseStream.Position -= 0x200 - 4;
            Distribution = (DistributionType)reader.ReadByte();
            ContentType  = (ContentType)reader.ReadByte();
            CryptoType   = reader.ReadByte();
            KaekInd      = reader.ReadByte();
            NcaSize      = reader.ReadInt64();
            TitleId      = reader.ReadUInt64();
            reader.BaseStream.Position += 4;

            SdkVersion  = new TitleVersion(reader.ReadUInt32());
            CryptoType2 = reader.ReadByte();
            reader.BaseStream.Position += 0xF;

            RightsId = reader.ReadBytes(0x10);

            for (int i = 0; i < 4; i++)
            {
                SectionEntries[i] = new NcaSectionEntry(reader);
            }

            for (int i = 0; i < 4; i++)
            {
                SectionHashes[i] = reader.ReadBytes(0x20);
            }

            for (int i = 0; i < 4; i++)
            {
                EncryptedKeys[i] = reader.ReadBytes(0x10);
            }

            reader.BaseStream.Position += 0xC0;

            for (int i = 0; i < 4; i++)
            {
                FsHeaders[i] = new NcaFsHeader(reader);
            }
        }
Example #3
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(data, offset);

            byte[] actualHash = Crypto.ComputeSha256(data, 0, data.Length);

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

            return(Validity.Invalid);
        }