Beispiel #1
0
 public static void AddIfExists(this List <NCCHRegion> list, NCCHRegion region)
 {
     if (region.Size != 0)
     {
         list.Add(region);
     }
 }
Beispiel #2
0
        private void ExtractExeFS(Stream output, NCCHRegion region, Keyslot secondaryKeyslot, bool close = true)
        {
            if (secondaryKeyslot == Keyslot.NCCH)
            {
                //if the secondary keyslot is also the original 0x2C NCCH Keyslot, don't bother decrypting anything in parts, and just shove the entire ExeFS through a CryptoStream
                Tools.CryptFileStreamPart(this.NCCHMemoryMappedFile, output, new AesCtrCryptoTransform(this.Cryptor.NormalKey[(int)Keyslot.NCCH], region.CTR), region.Offset, region.Size, close);
                return;
            }

            //here we go, i don't like this part

            byte[] header = new byte[0x200];

            using (MemoryMappedViewStream headerViewStream = this.NCCHMemoryMappedFile.CreateViewStream(region.Offset, 0x200))
            {
                header = Tools.CryptBytes(headerViewStream.ReadBytes(0x200), new AesCtrCryptoTransform(this.Cryptor.NormalKey[0x2C], region.CTR));
            }

            output.Write(header);

            //create dummy ExeFS class instance to figure out the locations of each file in the ExeFS
            ExeFS exefs = new ExeFS(header);

            //write decrypted header to output file
            foreach (ExeFSEntry entry in exefs.Entries)
            {
                byte[] CTR = (region.CTRInt + (entry.Offset / 16)).ToCTRBytes();

                AesCtrCryptoTransform transform = (NormalCryptoExeFSFiles.Contains(entry.Name)) ? new AesCtrCryptoTransform(this.Cryptor.NormalKey[(int)Keyslot.NCCH], CTR) : new AesCtrCryptoTransform(this.Cryptor.NormalKey[(int)secondaryKeyslot], CTR);

                using (MemoryMappedViewStream fileViewStream = this.NCCHMemoryMappedFile.CreateViewStream(region.Offset + entry.Offset, entry.Size))
                {
                    CryptoStream cs = new CryptoStream(output, transform, CryptoStreamMode.Write);

                    output.Seek(entry.Offset, SeekOrigin.Begin);

                    fileViewStream.CopyTo(cs);

                    cs.FlushFinalBlock();
                }
            }

            //sneaky way to make it gm9-like

            if (!(output.GetType() == typeof(MemoryMappedViewStream)))
            {
                output.SetLength(Tools.RoundUp(output.Length, 0x200));
            }

            if (close)
            {
                output.Dispose();
            }
        }
Beispiel #3
0
        public void ExtractSection(NCCHSection section, Stream outputStream, bool decrypt = true, bool close = true)
        {
            if (this.Info.Flags.UsesEncryption && this.Cryptor == null && decrypt == true)
            {
                throw new ArgumentException("This NCCH is encrypted, and no Crypto Engine was provided to perform decryption.");
            }

            if (!this.Regions.Any(region => region.Type == section))
            {
                throw new ArgumentException($"The requested section ({Enum.GetName(typeof(NCCHSection), section)}) was not found inside this NCCH.");
            }

            NCCHRegion region = this.Regions.Find(region => region.Type == section);

            if (this.Info.Flags.UsesEncryption && decrypt && !NoCryptoSections.Contains(region.Type)) //if encrypted, user wants to decrypt, and the selected region is known to use encryption
            {
                Keyslot primaryKeyslot;
                Keyslot secondaryKeyslot;

                byte[] secondaryKeyY = new byte[16];

                if (this.Info.Flags.UsesFixedKey)
                {
                    primaryKeyslot   = ((this.Info.TitleID & (0x10 << 32)) > 0) ? Keyslot.FixedSystemKey : Keyslot.ZeroKey;
                    secondaryKeyslot = primaryKeyslot;
                }
                else
                {
                    primaryKeyslot   = Keyslot.NCCH;
                    secondaryKeyslot = secondaryKeyslot = this.Info.Flags.CryptoMethod switch
                    {
                        0x00 => Keyslot.NCCH,
                        0x01 => Keyslot.NCCH70,
                        0x0A => Keyslot.NCCH93,
                        0x0B => Keyslot.NCCH96,
                        _ => throw new Exception("Could not determine crypto type. This should NOT happen.")
                    };

                    if (this.Info.Flags.UsesSeed)
                    {
                        this.Info.LoadSeed(this.SeedDB);

                        secondaryKeyY = this.Info.SeededKeyY;
                    }
                    else
                    {
                        secondaryKeyY = this.Info.KeyY;
                    }
                }

                this.Cryptor.SetKeyslot("y", (int)primaryKeyslot, this.Info.KeyY.ToUnsignedBigInt());  //load primary key into keyslot
                this.Cryptor.SetKeyslot("y", (int)secondaryKeyslot, secondaryKeyY.ToUnsignedBigInt()); //load secondary key into keyslot

                //decrypts based on section
                switch (region.Type)
                {
                case NCCHSection.ExHeader:
                    Tools.CryptFileStreamPart(this.NCCHMemoryMappedFile, outputStream, new AesCtrCryptoTransform(this.Cryptor.NormalKey[(int)primaryKeyslot], region.CTR), region.Offset, region.Size, close);
                    break;

                case NCCHSection.RomFS:
                    //uses secondary keyslot for it's entirety
                    Tools.CryptFileStreamPart(this.NCCHMemoryMappedFile, outputStream, new AesCtrCryptoTransform(this.Cryptor.NormalKey[(int)secondaryKeyslot], region.CTR), region.Offset, region.Size, close);
                    break;

                case NCCHSection.ExeFS:
                    //can use two keyslots. because of this, I separated the ExeFS decryption into another method
                    ExtractExeFS(outputStream, region, secondaryKeyslot, close);
                    break;
                }
            }
            else //just extract the raw section, because no crypto is used or the user did not request decryption
            {
                Tools.ExtractFileStreamPart(this.NCCHMemoryMappedFile, outputStream, region.Offset, region.Size, close);
            }
        }