Exemplo n.º 1
0
        public NCCHRegion(NCCHSection type, long offset, long size, long tid = 0)
        {
            this.Type   = type;
            this.Offset = offset;
            this.Size   = size;

            if ((int)type < 4 && tid != 0)
            {
                BigInteger ctrAsBigInt = ((BigInteger)tid << 64 | (BigInteger)(int)type << 56);

                this.CTRInt = ctrAsBigInt;
                this.CTR    = ctrAsBigInt.ToCTRBytes();
            }
        }
Exemplo n.º 2
0
        private byte[] getNcchAesCounter(NCCHHeader header, NCCHSection type) //Function based on code from ctrtool's source: https://github.com/Relys/Project_CTR
        {
            byte[] counter = new byte[16];
            if (header.formatVersion == 2 || header.formatVersion == 0)
            {
                for (int i = 0; i < 8; ++i)
                {
                    counter[i] = header.titleId[header.titleId.Length - 1 - i];
                }
                counter[8] = (byte)type;
            }
            else if (header.formatVersion == 1)
            {
                UInt32 x = 0;
                switch (type)
                {
                case NCCHSection.ExHeader:
                    x = 0x200;     //ExHeader is always 0x200 bytes into the NCCH
                    break;

                case NCCHSection.ExeFS:
                    x = header.exefsOffset * MEDIAUNITSIZE;
                    break;

                case NCCHSection.RomFS:
                    x = header.romfsOffset * MEDIAUNITSIZE;
                    break;
                }
                for (int i = 0; i < 8; ++i)
                {
                    counter[i] = header.titleId[i];
                }
                counter[12] = (byte)((x >> 24) & 0xFF);
                counter[13] = (byte)((x >> 16) & 0xFF);
                counter[14] = (byte)((x >> 8) & 0xFF);
                counter[15] = (byte)(x & 0xFF);
            }
            return(counter);
        }
Exemplo n.º 3
0
 //Function based on code from ctrtool's source: https://github.com/Relys/Project_CTR
 private byte[] getNcchAesCounter(NCCHHeader header, NCCHSection type)
 {
     byte[] counter = new byte[16];
     if(header.formatVersion == 2 || header.formatVersion == 0)
     {
         for(int i = 0; i < 8; ++i)
         {
             counter[i] = header.titleId[header.titleId.Length - 1 - i];
         }
         counter[8] = (byte) type;
     }
     else if(header.formatVersion == 1)
     {
         UInt32 x = 0;
         switch(type)
         {
             case NCCHSection.ExHeader:
                 x = 0x200; //ExHeader is always 0x200 bytes into the NCCH
                 break;
             case NCCHSection.ExeFS:
                 x = header.exefsOffset * MEDIAUNITSIZE;
                 break;
             case NCCHSection.RomFS:
                 x = header.romfsOffset * MEDIAUNITSIZE;
                 break;
         }
         for(int i = 0; i < 8; ++i)
         {
             counter[i] = header.titleId[i];
         }
         counter[12] = (byte) ((x >> 24) & 0xFF);
         counter[13] = (byte) ((x >> 16) & 0xFF);
         counter[14] = (byte) ((x >> 8) & 0xFF);
         counter[15] = (byte) (x & 0xFF);
     }
     return counter;
 }
Exemplo n.º 4
0
        private NCCHInfoEntry parseNCCHSection(NCCHHeader header, NCCHSection type, byte[] keyY, bool uses7xCrypto, bool usesSeedCrypto, bool print, string indent)
        {
            NCCHInfoEntry entry = new NCCHInfoEntry();
            entry.keyY = keyY;
            entry.reserved = 0x00000000;
            entry.uses7xcrypto = (UInt32) (uses7xCrypto ? 0x00000001 : 0x00000000);
            entry.uses9xcrypto = (UInt32) (usesSeedCrypto ? 0x00000001 : 0x00000000);
            entry.outputname = new byte[112];

            string sectionname;
            uint offset;
            uint sectionsize;

            switch(type)
            {
                case NCCHSection.ExHeader:
                    sectionname = "ExHeader";
                    offset = 0x200; //Always 0x200
                    sectionsize = header.exhdrSize * MEDIAUNITSIZE;
                    break;
                case NCCHSection.ExeFS:
                    sectionname = "ExeFS";
                    offset = header.exefsOffset * MEDIAUNITSIZE;
                    sectionsize = header.exefsSize * MEDIAUNITSIZE;
                    break;
                case NCCHSection.RomFS:
                    sectionname = "RomFS";
                    offset = header.romfsOffset * MEDIAUNITSIZE;
                    sectionsize = header.romfsSize * MEDIAUNITSIZE;
                    break;
                default:
                    Console.Error.WriteLine("Illegal NCCH Section type provided!");
                    Environment.Exit(1);
                    return entry; //Needed to compile
            }

            entry.counter = getNcchAesCounter(header, type);
            entry.titleID = new byte[8];
            Array.Copy(header.programId, 0, entry.titleID, 0, 8);

            //Compute section size in MB, rounding up to the next MB
            uint sectionMb = sectionsize / BYTES_PER_MEGABYTE; //Rounding down in this step
            uint remainder = sectionsize % BYTES_PER_MEGABYTE;
            if(remainder != 0)
            {
                ++sectionMb;
            }
            entry.size = sectionMb;

            if(print)
            {
                Console.WriteLine(String.Format(indent + "{0} offset:  {1:X8}", sectionname, offset));
                Console.WriteLine(String.Format(indent + "{0} counter: {1}", sectionname, ToHexString(entry.counter)));
                Console.WriteLine(String.Format(indent + "{0} Megabytes(rounded up): {1}", sectionname, sectionMb));
            }

            //TODO
            //return struct.pack('<16s16sIIIIQ', str(counter), str(keyY), sectionMb, 0, usesSeedCrypto, uses7xCrypto, titleId)

            return entry;
        }
Exemplo n.º 5
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);
            }
        }
Exemplo n.º 6
0
        private NCCHInfoEntry parseNCCHSection(NCCHHeader header, NCCHSection type, byte[] keyY, bool uses7xCrypto, bool usesSeedCrypto, bool print, string indent)
        {
            NCCHInfoEntry entry = new NCCHInfoEntry();

            entry.keyY         = keyY;
            entry.reserved     = 0x00000000;
            entry.uses7xcrypto = (UInt32)(uses7xCrypto ? 0x00000001 : 0x00000000);
            entry.uses9xcrypto = (UInt32)(usesSeedCrypto ? 0x00000001 : 0x00000000);
            entry.outputname   = new byte[112];

            string sectionname;
            uint   offset;
            uint   sectionsize;

            switch (type)
            {
            case NCCHSection.ExHeader:
                sectionname = "ExHeader";
                offset      = 0x200; //Always 0x200
                sectionsize = header.exhdrSize * MEDIAUNITSIZE;
                break;

            case NCCHSection.ExeFS:
                sectionname = "ExeFS";
                offset      = header.exefsOffset * MEDIAUNITSIZE;
                sectionsize = header.exefsSize * MEDIAUNITSIZE;
                break;

            case NCCHSection.RomFS:
                sectionname = "RomFS";
                offset      = header.romfsOffset * MEDIAUNITSIZE;
                sectionsize = header.romfsSize * MEDIAUNITSIZE;
                break;

            default:
                Console.Error.WriteLine("Illegal NCCH Section type provided!");
                Environment.Exit(1);
                return(entry);    //Needed to compile
            }

            entry.counter = getNcchAesCounter(header, type);
            entry.titleID = new byte[8];
            Array.Copy(header.programId, 0, entry.titleID, 0, 8);

            //Compute section size in MB, rounding up to the next MB
            uint sectionMb = sectionsize / BYTES_PER_MEGABYTE; //Rounding down in this step
            uint remainder = sectionsize % BYTES_PER_MEGABYTE;

            if (remainder != 0)
            {
                ++sectionMb;
            }
            entry.size = sectionMb;

            if (print)
            {
                Console.WriteLine(String.Format(indent + "{0} offset:  {1:X8}", sectionname, offset));
                Console.WriteLine(String.Format(indent + "{0} counter: {1}", sectionname, ToHexString(entry.counter)));
                Console.WriteLine(String.Format(indent + "{0} Megabytes(rounded up): {1}", sectionname, sectionMb));
            }


            //TODO
            //return struct.pack('<16s16sIIIIQ', str(counter), str(keyY), sectionMb, 0, usesSeedCrypto, uses7xCrypto, titleId)

            return(entry);
        }