예제 #1
0
파일: Switch.cs 프로젝트: mhdasding/Kuriimu
        public static void DecryptNCA(Stream input, long offset)
        {
            var keyset = new Keyset();

            using (var bw = new BinaryWriterX(input, true))
                using (var br = new BinaryReaderX(input, true))
                {
                    br.BaseStream.Position = offset;

                    //Decrypt NCA Header
                    var enc_header  = br.ReadBytes(0x400);
                    var magic       = enc_header.GetElements(0x200, 4).Aggregate("", (o, b) => o + (char)b);
                    var headerPart  = new byte[0x400];
                    var headerPart2 = new byte[0x800];
                    if (magic != "NCA2" && magic != "NCA3")
                    {
                        headerPart             = Decryption.XTS128(enc_header, keyset.ncaHeaderKey, 0x200, true);
                        magic                  = headerPart.GetElements(0x200, 4).Aggregate("", (o, b) => o + (char)b);
                        bw.BaseStream.Position = offset;
                        bw.Write(headerPart);
                        if (magic == "NCA3")
                        {
                            headerPart2            = Decryption.XTS128(br.ReadBytes(0x800), keyset.ncaHeaderKey, 0x200, true, 2);
                            bw.BaseStream.Position = offset + 0x400;
                            bw.Write(headerPart2);
                        }
                        else if (magic == "NCA2")
                        {
                            for (int i = 0; i < 4; i++)
                            {
                                var buffer = Decryption.XTS128(br.ReadBytes(0x200), keyset.ncaHeaderKey, 0x200, true);
                                Array.Copy(buffer, 0, headerPart2, i * 0x200, 0x200);
                                bw.BaseStream.Position -= 0x200;
                                bw.Write(buffer);
                            }
                        }
                        else
                        {
                            throw new InvalidDataException("Invalid NCA Header! Are the keys correct?");
                        }
                    }
                    else
                    {
                        headerPart  = enc_header;
                        headerPart2 = br.ReadBytes(0x800);
                    }


                    //Get crypto_type for master_key
                    var cryptoType = (headerPart[0x220] > headerPart[0x206]) ? headerPart[0x220] : headerPart[0x206];
                    if (cryptoType == 1)
                    {
                        cryptoType--;
                    }

                    //RightsID
                    bool hasRightsID = false;
                    for (int i = 0; i < 0x10; i++)
                    {
                        if (headerPart[0x230 + i] != 0)
                        {
                            hasRightsID = true;
                            break;
                        }
                    }

                    /* Explanation:
                     * - if a RightsID is set, an external titleKey is needed. This titleKey is contained in a ticket,
                     *   most likely installed on the system by download titles from eshop
                     * - if no RightsID is set, the nca internal keyarea is used to decrypt the contents
                     */

                    byte[] dec_title_key = null;
                    byte[] dec_key_area  = null;
                    if (!hasRightsID)
                    {
                        //Decrypt keyarea
                        var keyIndex = headerPart[0x207];
                        if (keyIndex > 2)
                        {
                            throw new InvalidDataException($"NCA KeyIndex must be 0-2. Found KeyIndex: {keyIndex}");
                        }
                        dec_key_area = Decryption.ECB128(headerPart.GetElements(0x300, 0x40), keyset.keyAreaKeys[cryptoType][keyIndex]);
                    }
                    else
                    {
                        //Decrypt title_key
                        var title_key = InputBox.Show("Input Titlekey:", "Decrypt NCA").Hexlify(16);
                        dec_title_key = Decryption.ECB128(title_key, keyset.titleKeks[cryptoType]);
                    }

                    //Read out section crypto
                    List <SectionEntry> sectionList = new BinaryReaderX(new MemoryStream(headerPart.GetElements(0x240, 0x40))).ReadMultiple <SectionEntry>(4);
                    for (int i = 0; i < 4; i++)
                    {
                        if (sectionList[i].mediaOffset != 0 && sectionList[i].endMediaOffset != 0)
                        {
                            br.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;

                            if (hasRightsID)
                            {
                                var enc_buffer = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                var dec_buffer = Decryption.CTR128(enc_buffer, dec_title_key, GenerateCTR(i + 1, sectionList[i].mediaOffset * 0x200));
                                bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                bw.Write(dec_buffer);
                            }
                            else
                            {
                                var sectionCrypto = headerPart2[i * 0x200 + 0x4];
                                if (sectionCrypto == 0 || sectionCrypto > 4)
                                {
                                    throw new InvalidDataException($"SectionCrypto {i} must be 1-4. Found SectionCrypto: {sectionCrypto}");
                                }

                                switch (sectionCrypto)
                                {
                                //case 1 is NoCrypto
                                case 2:
                                    //XTS
                                    var enc_buffer = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                    var dec_buffer = Decryption.XTS128(enc_buffer, dec_key_area.GetElements(0, 0x20), 0x200);
                                    bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                    bw.Write(dec_buffer);
                                    break;

                                case 3:
                                    //CTR
                                    enc_buffer             = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                    dec_buffer             = Decryption.CTR128(enc_buffer, dec_key_area.GetElements(0x20, 0x10), GenerateCTR(i + 1, sectionList[i].mediaOffset * 0x200));
                                    bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                    bw.Write(dec_buffer);
                                    break;

                                case 4:
                                    //BKTR
                                    //stub
                                    break;
                                }

                                bw.BaseStream.Position = offset + 0x400 + i * 0x200 + 0x4;
                                bw.Write((byte)0x1);
                            }
                        }
                    }
                }
        }